# -*- coding:utf-8 -*-
# @Time : 21-8-9 下午1:35 
# @Author : zdy
# @File : UIMultiBaseCalibration.py
# desc:

from Class.GraphBase import GraphBase
from UI.MultiBaseCalibration import Ui_MultiBaseCalibration
from Class.Format import *
from Class.CSConfig import BaseCalibrationItem
from Class.VoltSignal import dataBase, VoltSignal
from Class.Factor import Factor
from Class.LSFit import Fit
import pyqtgraph as pg
from Class.Devices import *
from UIClass.UILinearity import UILinearity

import datetime, copy, os
from importQT import *

class UIMultiBaseCalibration(QDialog, Ui_MultiBaseCalibration):
    def __init__(self):
        super(UIMultiBaseCalibration, self).__init__()
        self.setupUi(self)
        self.setWindowTitle('基础校正')
        self.applyResource()
        self.baseItems = [[] for i in range(0, dataBase.maxChannel)]
        self.inittwData()
        self.initGraph()
        self.rbtn0.setText(E1)
        self.rbtn1.setText(E2)
        self.rbtn2.setText(E3)
        self.rbtn3.setText(E4)
        self.rbtn0.toggled.connect(self.switchChannel)
        self.rbtn1.toggled.connect(self.switchChannel)
        self.rbtn2.toggled.connect(self.switchChannel)
        self.rbtn3.toggled.connect(self.switchChannel)
        self.currentChannel = 0
        self.rbtn0.setChecked(1)

        # self.btnNew.clicked.connect(self.btnNew_clicked)
        # self.btnNew.setVisible(False)
        self.btnCalculation.clicked.connect(self.btnCalculation_clicked)
        self.btnDelete.clicked.connect(self.btnDelete_clicked)
        self.btnLinearity.clicked.connect(self.btnLinearity_clicked)


        self.setAcceptDrops(True)

    def applyResource(self):
        self.setWindowIcon(getIcon())

    def switchChannel(self, isChecked):
        if isChecked:
            if self.sender() == self.rbtn0:
                self.currentChannel =0
            if self.sender() == self.rbtn1:
                self.currentChannel =1
            if self.sender() == self.rbtn2:
                self.currentChannel =2
            if self.sender() == self.rbtn3:
                self.currentChannel =3
            self.bingDatas()
            self.setParams()

    def initGraph(self):
        self.graphBase = GraphBase(self)
        self.graph = self.graphBase.graphwiget
        self.graph.setLabel("left", "绝对质量(10ug)")
        self.graph.setLabel("bottom", "线性化后面积")
        self.gridLayout.addWidget(self.graph)
        self.curve =[]#用于存放绘制的曲线，清除的时候，直接清除这里就可以，以防self.graph.clear()清除数值显示标签

    def bingDatas(self):
        count = self.twData.rowCount()
        for i in range(count-1, -1,-1):
            self.twData.removeRow(i)
        self.setDatas(self.baseItems[self.currentChannel])

    def setParams(self):
        """根据当前参数，更新界面参数显示，绘制曲线图"""
        factor = device.config.factors[self.currentChannel]
        if deviceType == "CS":
            self.lblParams.setText("C1={:.{}f}".format(factor.baseK, 6) + os.linesep +
                                   "C2={:.{}f}".format(factor.baseB, 6) + os.linesep +
                                   "r={:.{}f}".format(factor.baseR, 6) + os.linesep
                                   )
        else:
            self.lblParams.setText("y = {:.{}f}".format(factor.baseK, 6)+" * x +"+ "{:.{}f}".format(factor.baseB, 6)+
                                   os.linesep +"r={:.{}f}".format(factor.baseR, 6)
                                   )
        self.lblR.setText("线性化系数 ={}".format(factor.linearity))
        for i in self.curve:
            i.clear()
            self.graph.removeItem(i)
        self.curve.clear()
        ptx = []
        pty = []
        for item in device.config.baseItems[self.currentChannel]:
            if item.include:
                ptx.append(item.area)
                pty.append(item.elementV)
            item.calculated = Factor.calculateResultFromArea(item.area, item.weight, item.flux, factor)
        if len(ptx) > 0:
            self.curve.append(self.graph.plot(x=ptx, y=pty, pen=None, symbol='o'))
            xe = max(ptx)
            ye = factor.baseK * xe + factor.baseB
            ys = factor.baseK * 0 + factor.baseB
            self.curve.append(self.graph.plot(x=[0, xe], y=[ys, ye], pen=pg.mkPen(color="r", width=2), style=Qt.DashLine))
        self.updateTWFromList()

    def inittwData(self):
        self.twData.setColumnCount(7)
        # 设置表头粗体
        self.twData.setHorizontalHeaderLabels(['日期', '样品名称', '序号', '标准值%', '计算值%', '线性化后面积', '包含'])
        font = self.twData.horizontalHeader().font()
        font.setBold(True)
        self.twData.horizontalHeader().setFont(font)
        # self.twData.setSelectionBehavior(QAbstractItemView.SelectRows)  # 整行选中的方式
        self.twData.setItemDelegate(DelegateResult(self, [3, 4], [5], [3], [3], False,None))  # 结果小数位数
        self.twData.horizontalHeader().setStretchLastSection(True)  # 最后一列填充
        self.twData.setColumnWidth(0, 200)
        # self.twData.verticalHeader().setVisible(False)  # 行首不可见
        self.twData.horizontalHeader().setSectionsClickable(False)  # 表头不可点击
        self.twData.cellChanged.connect(self.twData_cellChanged)
        for i in range(0, dataBase.maxChannel):
            if len(device.config.baseItems[i]) > 0:
                self.baseItems[i] = copy.deepcopy(device.config.baseItems[i])

    def twData_cellChanged(self, row, column):
        value = self.twData.item(row,column).data(0)
        ranges = self.twData.selectedRanges()
        count = len(ranges)
        rows = []
        for i in range(count):
            for j in range(ranges[i].topRow(), ranges[i].bottomRow() + 1):
                rows.append(j)
        self.twData.blockSignals(True)
        for i in rows:
            self.twData.item(i, column).setData(0,value)
        self.twData.blockSignals(False)

    def setData(self, data):
        '''
        向twData里添加一行数据
        :param data: BaseCalibrationItem
        :return:
        '''
        row = self.twData.rowCount()
        self.twData.insertRow(row)
        alignment = int(Qt.AlignHCenter | Qt.AlignVCenter)
        for i in range(7):
            item = QTableWidgetItem()
            if i == 0:
                item.setData(Qt.DisplayRole, data.id)
            elif i == 1:
                item.setData(Qt.DisplayRole, data.name)
            elif i == 2:
                item.setData(Qt.DisplayRole, data.num)
            elif i == 3:
                item.setData(Qt.DisplayRole, data.standard)
            elif i == 4:
                item.setData(Qt.DisplayRole, data.calculated)
            elif i == 5:
                item.setData(Qt.DisplayRole, data.area)
            elif i == 6:
                item = QTableWidgetItem(data.include)
                item.setCheckState(Qt.Checked if data.include else Qt.Unchecked)
            if i != 3 and i != 5:
                item.setFlags(item.flags() & (~Qt.ItemIsEditable))
            item.setTextAlignment(alignment)
            self.twData.setItem(row, i, item)
        # self.twData.setStyleSheet("QTableWidget::item{border:1px solid ;}")
        # self.twData.setGridStyle(Qt.SolidLine)  #设置边框样式
        self.twData.setShowGrid(True)  # 有数据时才起作用

    def setDatas(self, items):
        '''
        向twData里添加多行数据
        :param items: BaseCalibrationItem  s
        :return:
        '''
        self.twData.blockSignals(True)
        for data in items:
            self.setData(data)
        self.twData.blockSignals(False)

    def btnNew_clicked(self):
        '''新建一条数据'''
        data = BaseCalibrationItem()
        data.id = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        data.standard = 0.012
        data.area = 0.011
        data.input = True
        data.include = True
        self.setDatas([data])
        self.baseItems[self.currentChannel].append(data)

    def btnDelete_clicked(self):
        ranges = self.twData.selectedRanges()
        count = len(ranges)
        row = []
        for i in range(0, count):
            for j in range(ranges[i].topRow(), ranges[i].bottomRow() + 1):
                row.append(j)
        row.sort(key=int, reverse=True)  # 因为删除一行后，后面的行号都会变化，所以用sort方法将list进行降序排列
        self.twData.blockSignals(True)
        for i in row:
            self.twData.removeRow(i)
            self.baseItems[self.currentChannel].pop(i)
        self.twData.blockSignals(False)

    def btnCalculation_clicked(self):
        if self.currentChannel == -1:
            return
        if bool(1 - self.updateListFromTW()):
            return
        self.origin = self.chkOrigin.checkState() == Qt.Checked
        if len(self.baseItems[self.currentChannel]) > 0:
            areas = []
            results = []
            for item in self.baseItems[self.currentChannel]:
                if item.include:
                    if bool(1 - item.input):
                        vs = VoltSignal.loadAll(item.id)
                        if vs == None:
                            QMessageBox.warning(self, "提示", "找不到数据")
                            return
                        item.weight = vs.sampleWeight
                        item.blank = vs.factors[self.currentChannel].blank
                        item.flux = vs.fluxWeight
                        item.area = device.config.factors[self.currentChannel].\
                            calculateArea(vs.listT,vs.listData[ self.currentChannel],vs.average[self.currentChannel])- \
                                    device.config.factors[self.currentChannel].blankarea
                        factor = copy.copy(device.config.factors[self.currentChannel])
                        factor.calibration = 1
                        item.elementV = factor.calculateElementWeightFromStandard(item.standard, item.weight,
                                                                                  item.blank,item.flux)
                    areas.append(item.area)
                    results.append(item.elementV)
            if self.origin:
                results.insert(0, 0)
                areas.insert(0, 0)
            if len(areas) >= 2:
                params = Fit.LineFit(areas, results, self.origin)
                # linearity = device.config.factors[self.currentChannel].linearity
                # device.config.factors[self.currentChannel] = Factor()
                device.config.factors[self.currentChannel].baseR = Fit.Coefficient(areas, results)
                device.config.factors[self.currentChannel].baseK = params[0]
                device.config.factors[self.currentChannel].baseB = params[1]
                device.config.factors[self.currentChannel].orgin = self.origin
                # device.config.factors[self.currentChannel].linearity = linearity
                device.config.factors[self.currentChannel].calibration = 1.0
                # device.config.factors[self.currentChannel].xItem.clear()
                # device.config.factors[self.currentChannel].yItem.clear()
                # device.config.multiPointItems[self.currentChannel].clear()
                device.config.baseItems[self.currentChannel] = copy.deepcopy(self.baseItems[self.currentChannel])
                self.setParams()
                pass

    def updateListFromTW(self):
        """根据校正表更新baseItems中的标准值和包含
        :return 是否更新成功
        """
        rowcount = self.twData.rowCount()
        if rowcount > 0:
            for i in range(0, rowcount):
                id = self.twData.item(i, 0).text()
                items = list(filter(lambda x: x.id == id, self.baseItems[self.currentChannel]))
                if len(items) == 1:
                    try:
                        items[0].standard = float(self.twData.item(i, 3).text())
                        items[0].include = self.twData.item(i, 6).checkState() == Qt.Checked
                        items[0].area = float(self.twData.item(i, 5).text())
                    except Exception as ex:
                        QMessageBox.warning(self,"基础校正","数据异常")
                        return False
        return True

    def updateTWFromList(self):
        """根据baseItems更新校正表中的计算后"""
        self.twData.blockSignals(True)
        rowcount = self.twData.rowCount()
        if rowcount > 0:
            for i in range(rowcount):
                id = self.twData.item(i, 0).text()
                items = list(filter(lambda x: x.id == id, device.config.baseItems[self.currentChannel]))
                if len(items) == 1:
                    try:
                        self.twData.item(i, 4).setData(Qt.DisplayRole, items[0].calculated)
                        self.twData.item(i, 5).setData(Qt.DisplayRole, items[0].area)
                    except Exception as ex:
                        QMessageBox.warning(self,"基础校正","数据异常")
                        break
        self.twData.blockSignals(False)
        return True

    def btnLinearity_clicked(self):
        self.updateListFromTW()
        w = UILinearity(self.baseItems[self.currentChannel], self.currentChannel)
        w.setAttribute(Qt.WA_DeleteOnClose)
        w.setWindowFlag(Qt.WindowStaysOnTopHint)
        w.exec()
        self.lblR.setText("相关系数={}".format(device.config.factors[self.currentChannel].linearity))

    def dropEvent(self, a0: QDropEvent) -> None:
        """当拖拽操作在目标控件上被释放时，触发"""
        if a0.mimeData().hasText():
            dropstr = a0.mimeData().text()
            # print(dropstr)
            rowindexsstr = dropstr.split("&")
            rowIndexs = []
            for i in rowindexsstr:
                rowIndexs.append(int(i))
            count = len(rowIndexs)
            if count > 0:
                results = device.modelResult.getBaseItems(rowIndexs)
                if len(results) > 0:
                    self.setDatas(results)
                    for i in results:
                        self.baseItems[self.currentChannel].append(i)
        pass

    def dragEnterEvent(self, a0: QDragEnterEvent) -> None:
        """拖拽操作时，进入该控件时，触发该事件，"""
        if a0.mimeData().hasText():
            a0.setAccepted(True)
            # print("准备接收drag")
        else:
            a0.setAccepted(False)
            # print("drag不匹配")
        pass

import sys

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = UIMultiBaseCalibration()
    w.setAttribute(Qt.WA_DeleteOnClose)
    w.exec()
    sys.exit(0)
